home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / src / Fl_Tabs.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-07-22  |  7.5 KB  |  266 lines

  1. //
  2. // "$Id: Fl_Tabs.cxx,v 1.6.2.2 1999/07/22 07:27:11 bill Exp $"
  3. //
  4. // Tab widget for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. // This is the "file card tabs" interface to allow you to put lots and lots
  27. // of buttons and switches in a panel, as popularized by many toolkits.
  28.  
  29. // Each child widget is a card, and it's label() is printed on the card tab.
  30. // Clicking the tab makes that card visible.
  31.  
  32. #include <FL/Fl.H>
  33. #include <FL/Fl_Tabs.H>
  34. #include <FL/fl_draw.H>
  35.  
  36. #define BORDER 10
  37. #define TABSLOPE 8
  38.  
  39. // return the left edges of each tab (plus a fake left edge for a tab
  40. // past the right-hand one).  These position are actually of the left
  41. // edge of the slope.  They are either seperated by the correct distance
  42. // or by TABSLOPE or by zero.
  43. // Return value is the index of the selected item.
  44.  
  45. int Fl_Tabs::tab_positions(int* p, int* w) {
  46.   int selected = 0;
  47.   Fl_Widget*const* a = array();
  48.   int i;
  49.   p[0] = 0;
  50.   for (i=0; i<children(); i++) {
  51.     Fl_Widget* o = *a++;
  52.     if (o == value_) selected = i;
  53.     if (o->label()) {
  54.       int wt = 0; int ht = 0; o->measure_label(wt,ht);
  55.       w[i] = wt+TABSLOPE;
  56.       if (2*TABSLOPE > w[i]) w[i] = 2*TABSLOPE;
  57.     } else 
  58.       w[i] = 2*TABSLOPE;
  59.     p[i+1] = p[i]+w[i];
  60.   }
  61.   int r = this->w()-TABSLOPE-1;
  62.   if (p[i] <= r) return selected;
  63.   // uh oh, they are too big:
  64.   // pack them against right edge:
  65.   p[i] = r;
  66.   for (i = children(); i--;) {
  67.     int l = r-w[i];
  68.     if (p[i+1]-TABSLOPE < l) l = p[i+1]-TABSLOPE;
  69.     if (p[i] <= l) break;
  70.     p[i] = l;
  71.     r -= TABSLOPE;
  72.   }
  73.   // pack them against left edge and truncate width if they still don't fit:
  74.   for (i = 0; i<children(); i++) {
  75.     if (p[i] >= i*TABSLOPE) break;
  76.     p[i] = i*TABSLOPE;
  77.     int W = this->w()-1-TABSLOPE*(children()-i) - p[i];
  78.     if (w[i] > W) w[i] = W;
  79.   }
  80.   // adjust edges according to visiblity:
  81.   for (i = children(); i > selected; i--) {
  82.     p[i] = p[i-1]+w[i-1];
  83.   }
  84.   return selected;
  85. }
  86.  
  87. // return space needed for tabs.  Negative to put them on the bottom:
  88. int Fl_Tabs::tab_height() {
  89.   int H = h();
  90.   int H2 = y();
  91.   Fl_Widget*const* a = array();
  92.   for (int i=children(); i--;) {
  93.     Fl_Widget* o = *a++;
  94.     if (o->y() < y()+H) H = o->y()-y();
  95.     if (o->y()+o->h() > H2) H2 = o->y()+o->h();
  96.   }
  97.   H2 = y()+h()-H2;
  98.   if (H2 > H) {
  99.     H = H2-Fl::box_dy(box());
  100.     return (H <= 0) ? 0 : -H;
  101.   } else {
  102.     H = H-Fl::box_dy(box());
  103.     return (H <= 0) ? 0 : H;
  104.   }
  105. }
  106.  
  107. // this is used by fluid to pick tabs:
  108. Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
  109.   int H = tab_height();
  110.   if (H < 0) {
  111.     if (event_y > y()+h() || event_y < y()+h()+H) return 0;
  112.   } else {
  113.     if (event_y > y()+H || event_y < y()) return 0;
  114.   }
  115.   if (event_x < x()) return 0;
  116.   int p[128], w[128];
  117.   int selected = tab_positions(p, w);
  118.   int d = (event_y-(H>=0?y():y()+h()))*TABSLOPE/H;
  119.   for (int i=0; i<children(); i++) {
  120.     if (event_x < x()+p[i+1]+(i<selected ? TABSLOPE-d : d)) return child(i);
  121.   }
  122.   return 0;
  123. }
  124.  
  125. int Fl_Tabs::handle(int event) {
  126.  
  127.   Fl_Widget *o;
  128.  
  129.   switch (event) {
  130.  
  131.   case FL_PUSH: {
  132.     int H = tab_height();
  133.     if (H >= 0) {
  134.       if (Fl::event_y() > y()+H) goto DEFAULT;
  135.     } else {
  136.       if (Fl::event_y() < y()+h()+H) goto DEFAULT;
  137.     }}
  138.   case FL_DRAG:
  139.   case FL_RELEASE:
  140.     o = which(Fl::event_x(), Fl::event_y());
  141.     if (event == FL_RELEASE) {push(0); if (o) value(o);}
  142.     else push(o);
  143.     return 1;
  144.  
  145.   default:
  146.   DEFAULT:
  147.     value(); // initialize value & visibility if value_ == 0
  148.     return Fl_Group::handle(event);
  149.  
  150.   }
  151. }
  152.  
  153. int Fl_Tabs::push(Fl_Widget *o) {
  154.   if (push_ == o) return 0;
  155.   if (push_ && push_ != value_ || o && o != value_) damage(FL_DAMAGE_EXPOSE);
  156.   push_ = o;
  157.   return 1;
  158. }
  159.  
  160. Fl_Widget* Fl_Tabs::value() {
  161.   Fl_Widget *v = value_;
  162.   if (!v) {
  163.     // If value() has not been called, find first visible() child:
  164.     Fl_Widget*const* a = array();
  165.     for (int i=children(); i--;) {
  166.       Fl_Widget* o = *a++;
  167.       if (v) o->hide();
  168.       else if (o->visible()) v = o;
  169.     }
  170.     if (!v) return 0; // no children...
  171.     value_ = v;
  172.   }
  173.   return v;
  174. }
  175.  
  176. int Fl_Tabs::value(Fl_Widget *o) {
  177.   if (value_ == o) return 0;
  178.   Fl_Widget* oldvalue = value_;
  179.   value_ = o;
  180.   if (o) o->show();
  181.   if (oldvalue) oldvalue->hide();
  182.   redraw();
  183.   do_callback();
  184.   return 1;
  185. }
  186.  
  187. enum {LEFT, RIGHT, SELECTED};
  188.  
  189. void Fl_Tabs::draw() {
  190.   Fl_Widget *v = value();
  191.   int H = tab_height();
  192.   if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing:
  193.     fl_clip(x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H));
  194.     draw_box(box(), x(), y(), w(), h(), v ? v->color() : color());
  195.     fl_pop_clip();
  196.     if (v) draw_child(*v);
  197.   } else { // redraw the child
  198.     if (v) update_child(*v);
  199.   }
  200.   if (!v) return;
  201.  
  202.   if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL)) {
  203.     int p[128]; int w[128];
  204.     int selected = tab_positions(p,w);
  205.     int i;
  206.     Fl_Widget*const* a = array();
  207.     for (i=0; i<selected; i++)
  208.       draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], LEFT);
  209.     for (i=children()-1; i > selected; i--)
  210.       draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], RIGHT);
  211.     i = selected;
  212.     draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], SELECTED);
  213.   }
  214. }
  215.  
  216. void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
  217.   if (x2 < x1+W) {
  218.     if (what == LEFT) {
  219.       if (x1+W < x2+TABSLOPE) x2 = x1+W;
  220.       else x2 += TABSLOPE;
  221.     } else {
  222.       if (x1+W < x2+TABSLOPE) x1 = x2-W;
  223.       else x1 -= TABSLOPE;
  224.     }
  225.   }
  226.   int sel = (what == SELECTED);
  227.   fl_color(o->color());
  228.   if (H >= 0) {
  229.     fl_polygon(x1, y()+H+sel, x1+TABSLOPE, y(), x2, y(),
  230.            x2+TABSLOPE, y()+H+sel);
  231.     fl_color(!sel && o==push_ ? FL_DARK3 : FL_LIGHT3);
  232.     fl_line(x1, y()+H, x1+TABSLOPE, y(), x2, y());
  233.     if (sel) {
  234.       if (x1>x()) fl_xyline(x(), y()+H, x1);
  235.       if (x2+TABSLOPE < x()+w()-1) fl_xyline(x2+TABSLOPE, y()+H, x()+w()-1);
  236.     }
  237.     fl_color(!sel && o==push_ ? FL_LIGHT3 : FL_DARK3);
  238.     fl_line(x2, y(), x2+TABSLOPE, y()+H);
  239.   } else {
  240.     fl_polygon(x1, y()+h()+H-sel, x1+TABSLOPE, y()+h(), x2, y()+h(),
  241.            x2+TABSLOPE, y()+h()+H-sel);
  242.     fl_color(!sel && o==push_ ? FL_LIGHT3 : FL_DARK3);
  243.     fl_line(x1+TABSLOPE, y()+h()-1, x2, y()+h()-1, x2+TABSLOPE, y()+h()+H);
  244.     if (sel) {
  245.       if (x1>x()) fl_xyline(x(), y()+h()+H, x1);
  246.       if (x2+TABSLOPE < x()+w()-1) fl_xyline(x2+TABSLOPE, y()+h()+H,x()+w()-1);
  247.     }
  248.     fl_color(!sel && o==push_ ? FL_DARK3 : FL_LIGHT3);
  249.     fl_line(x1, y()+h()+H, x1+TABSLOPE, y()+h()-1);
  250.   }
  251.   if (W > TABSLOPE)
  252.     o->draw_label(what==LEFT ? x1+TABSLOPE : x2-W+TABSLOPE,
  253.           y()+(H<0?h()+H-3:0), W-TABSLOPE,
  254.           (H<0?-H:H)+3, FL_ALIGN_CENTER);
  255. }
  256.  
  257. Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) :
  258.   Fl_Group(X,Y,W,H,l) {
  259.     box(FL_THIN_UP_BOX);
  260.     value_ = push_ = 0;
  261. }
  262.  
  263. //
  264. // End of "$Id: Fl_Tabs.cxx,v 1.6.2.2 1999/07/22 07:27:11 bill Exp $".
  265. //
  266.